package org.drools.shapes.xsd; import org.coode.owlapi.manchesterowlsyntax.ManchesterOWLSyntaxOntologyFormat; import org.drools.KnowledgeBase; import org.drools.KnowledgeBaseFactory; import org.drools.RuntimeDroolsException; import org.drools.builder.KnowledgeBuilder; import org.drools.builder.KnowledgeBuilderFactory; import org.drools.builder.ResourceType; import org.drools.io.impl.ClassPathResource; import org.drools.runtime.StatefulKnowledgeSession; import org.drools.runtime.rule.Variable; import org.semanticweb.HermiT.Reasoner; import org.semanticweb.owlapi.apibinding.OWLManager; import org.semanticweb.owlapi.model.IRI; import org.semanticweb.owlapi.model.OWLAxiom; import org.semanticweb.owlapi.model.OWLDataFactory; import org.semanticweb.owlapi.model.OWLOntology; import org.semanticweb.owlapi.model.OWLOntologyCreationException; import org.semanticweb.owlapi.model.OWLOntologyFormat; import org.semanticweb.owlapi.model.OWLOntologyID; import org.semanticweb.owlapi.model.OWLOntologyManager; import org.semanticweb.owlapi.model.OWLOntologyStorageException; import org.semanticweb.owlapi.reasoner.InferenceType; import org.semanticweb.owlapi.reasoner.NullReasonerProgressMonitor; import org.semanticweb.owlapi.reasoner.OWLReasoner; import org.semanticweb.owlapi.reasoner.OWLReasonerConfiguration; import org.semanticweb.owlapi.reasoner.OWLReasonerFactory; import org.semanticweb.owlapi.reasoner.ReasonerProgressMonitor; import org.semanticweb.owlapi.reasoner.SimpleConfiguration; import org.semanticweb.owlapi.util.InferredAxiomGenerator; import org.semanticweb.owlapi.util.InferredClassAssertionAxiomGenerator; import org.semanticweb.owlapi.util.InferredDataPropertyCharacteristicAxiomGenerator; import org.semanticweb.owlapi.util.InferredEquivalentClassAxiomGenerator; import org.semanticweb.owlapi.util.InferredEquivalentDataPropertiesAxiomGenerator; import org.semanticweb.owlapi.util.InferredEquivalentObjectPropertyAxiomGenerator; import org.semanticweb.owlapi.util.InferredInverseObjectPropertiesAxiomGenerator; import org.semanticweb.owlapi.util.InferredObjectPropertyCharacteristicAxiomGenerator; import org.semanticweb.owlapi.util.InferredOntologyGenerator; import org.semanticweb.owlapi.util.InferredPropertyAssertionGenerator; import org.semanticweb.owlapi.util.InferredSubClassAxiomGenerator; import org.semanticweb.owlapi.util.InferredSubDataPropertyAxiomGenerator; import org.semanticweb.owlapi.util.InferredSubObjectPropertyAxiomGenerator; import org.semanticweb.owlapi.vocab.Namespaces; import org.w3._2001.xmlschema.Import; import org.w3._2001.xmlschema.Include; import org.w3._2001.xmlschema.OpenAttrs; import org.w3._2001.xmlschema.Redefine; import org.w3._2001.xmlschema.Schema; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.validation.SchemaFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Set; public class Xsd2OwlImpl implements Xsd2Owl { private static Xsd2OwlImpl instance; public static Xsd2Owl getInstance() { if ( instance == null ) { instance = new Xsd2OwlImpl(); } return instance; } private KnowledgeBase kBase; private static List<InferredAxiomGenerator<? extends OWLAxiom>> fullAxiomGenerators; { fullAxiomGenerators = Collections.unmodifiableList( new ArrayList<InferredAxiomGenerator<? extends OWLAxiom>>( Arrays.asList( new InferredClassAssertionAxiomGenerator(), new InferredDataPropertyCharacteristicAxiomGenerator(), new InferredEquivalentClassAxiomGenerator(), new InferredEquivalentDataPropertiesAxiomGenerator(), new InferredEquivalentObjectPropertyAxiomGenerator(), new InferredInverseObjectPropertiesAxiomGenerator(), new InferredObjectPropertyCharacteristicAxiomGenerator(), new InferredPropertyAssertionGenerator(), new InferredSubClassAxiomGenerator(), new InferredSubDataPropertyAxiomGenerator(), new InferredSubObjectPropertyAxiomGenerator() ))); } protected Xsd2OwlImpl() { System.out.println( "Creating converter...." ); kBase = initKBase(); System.out.println( "Created converter...." ); } private KnowledgeBase initKBase() { KnowledgeBuilder kBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kBuilder.add( new ClassPathResource( "org/drools/shapes/xsd/drl/xsd2owl.drl" ), ResourceType.DRL ); if ( kBuilder.hasErrors() ) { throw new RuntimeDroolsException( kBuilder.getErrors().toString() ); } kBase = KnowledgeBaseFactory.newKnowledgeBase(); kBase.addKnowledgePackages( kBuilder.getKnowledgePackages() ); return kBase; } public URL getSchemaURL( String schemaLocation ) { return Thread.currentThread().getContextClassLoader().getResource( schemaLocation ); } public Schema parse( URL schemaLocation ) { try { System.out.println( "Parsing schema.... " + schemaLocation ); JAXBContext context = JAXBContext.newInstance( Schema.class.getPackage().getName() ); URL metaSchemaURL = new ClassPathResource( "org/drools/shapes/xsd/xmlschema.xsd" ).getURL(); javax.xml.validation.Schema metax = SchemaFactory.newInstance( Namespaces.XSD.toString().replace( "#", "" ) ).newSchema( metaSchemaURL ); Unmarshaller loader = context.createUnmarshaller(); loader.setSchema( metax ); Schema schema = (Schema) loader.unmarshal( new File( schemaLocation.toURI() ) ); System.out.println( "Parsed schema...." ); if ( schema.getTargetNamespace() == null ) { schema.setTargetNamespace( "" ); } return schema; } catch ( Exception e ) { e.printStackTrace(); return null; } } public OWLOntology transform( Schema schema, URL schemaURL, boolean verbose, boolean checkConsistency ) { System.out.println( "Transforming...." ); StatefulKnowledgeSession kSession = kBase.newStatefulKnowledgeSession(); OWLOntology ontology = null; try { OWLOntologyManager manager = OWLManager.createOWLOntologyManager(); OWLDataFactory factory = manager.getOWLDataFactory(); ontology = manager.createOntology( new OWLOntologyID( IRI.create( schema.getTargetNamespace() ), IRI.create( schema.getTargetNamespace() + "/" + ( schema.getVersion() != null ? schema.getVersion() : "1.0" ) ) ) ); kSession.setGlobal( "ontology", ontology ); kSession.setGlobal( "manager", manager ); kSession.setGlobal( "factory", factory ); kSession.setGlobal( "validating", new Boolean( checkConsistency ) ); visit( schema, schemaURL, kSession, manager ); if ( verbose ) { try { manager.saveOntology( ontology, new ManchesterOWLSyntaxOntologyFormat(), System.out); } catch ( OWLOntologyStorageException e ) { e.printStackTrace(); } } if ( checkConsistency ) { launchReasoner( ontology, fullAxiomGenerators ); } } catch ( Exception e ) { e.printStackTrace(); try { return OWLManager.createOWLOntologyManager().createOntology(); } catch (OWLOntologyCreationException e1) { e1.printStackTrace(); return null; } } finally { kSession.dispose(); } System.out.println( "DONE!" ); return ontology; } private String getPrefix( String targetNamespace ) { return targetNamespace.endsWith( "/" ) || targetNamespace.endsWith( "#" ) || targetNamespace.endsWith( ":" ) ? targetNamespace : targetNamespace + "#"; } private void visit( Schema schema, URL schemaLocation, StatefulKnowledgeSession kSession, OWLOntologyManager manager ) throws MalformedURLException { for ( OpenAttrs ext : schema.getIncludeOrImportOrRedefine() ) { if ( ext instanceof Include ) { Include include = (Include) ext; URL url = new URL( schemaLocation, include.getSchemaLocation() ); Schema sub = parse( url ); visit( sub, url, kSession, manager ); } else if ( ext instanceof Import ) { Import imp = (Import) ext; URL url = new URL( schemaLocation, imp.getSchemaLocation() ); Schema sub = parse( url ); visit( sub, url, kSession, manager ); } else if ( ext instanceof Redefine ) { Redefine redefine = (Redefine) ext; throw new UnsupportedOperationException( "Implement redefines" ); } } System.out.println( "Visiting schema.... " ); kSession.setGlobal( "tns", schema.getTargetNamespace() ); // kSession.insert( schema ); new Jaxplorer( schema ).deepInsert( kSession ); kSession.fireAllRules(); System.out.println( "Visited, now adding axioms " ); Set set = (Set) kSession.getQueryResults( "axioms", Variable.v ).iterator().next().get( "$set" ); OWLOntology ontology = (OWLOntology) kSession.getGlobal( "ontology" ); for ( Object ax : set ) { manager.addAxiom( ontology, (OWLAxiom) ax ); } System.out.println( "Done with schema.... " ); } public boolean stream( OWLOntology onto, OutputStream stream, OWLOntologyFormat format ) { try { onto.getOWLOntologyManager().saveOntology( onto, format, stream ); return true; } catch (OWLOntologyStorageException e) { return false; } } private void launchReasoner( OWLOntology ontoDescr, List<InferredAxiomGenerator<? extends OWLAxiom>> axiomGenerators ) { long now = new Date().getTime(); System.err.println( " START REASONER " ); InferredOntologyGenerator reasoner = initReasoner( ontoDescr, axiomGenerators ); reasoner.fillOntology( ontoDescr.getOWLOntologyManager(), ontoDescr ); System.err.println( " STOP REASONER : time elapsed >> " + ( new Date().getTime() - now ) ); } protected InferredOntologyGenerator initReasoner( OWLOntology ontoDescr, List<InferredAxiomGenerator<? extends OWLAxiom>> axiomGenerators ) { ReasonerProgressMonitor progressMonitor = new NullReasonerProgressMonitor(); //new ConsoleProgressMonitor(); OWLReasonerConfiguration config = new SimpleConfiguration(progressMonitor); OWLReasonerFactory reasonerFactory = new Reasoner.ReasonerFactory(); OWLReasoner owler = reasonerFactory.createReasoner( ontoDescr, config ); owler.precomputeInferences( InferenceType.CLASS_HIERARCHY, InferenceType.CLASS_ASSERTIONS, InferenceType.DATA_PROPERTY_ASSERTIONS, InferenceType.DATA_PROPERTY_HIERARCHY, InferenceType.DIFFERENT_INDIVIDUALS, InferenceType.DISJOINT_CLASSES, InferenceType.OBJECT_PROPERTY_ASSERTIONS, InferenceType.OBJECT_PROPERTY_HIERARCHY, InferenceType.SAME_INDIVIDUAL ); return new InferredOntologyGenerator( owler, axiomGenerators ); } public String compactXMLSchema( String resourceName ) throws IOException, ParserConfigurationException, SAXException, XPathExpressionException, TransformerException, URISyntaxException { ClassPathResource cpr = new ClassPathResource( resourceName ); XPathFactory xpathFactory = XPathFactory.newInstance(); XPath xPath = xpathFactory.newXPath(); DocumentBuilderFactory doxFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = doxFactory.newDocumentBuilder(); InputSource is = new InputSource( new FileInputStream( new File( cpr.getURL().toURI().getPath() ) ) ); Document dox = builder.parse( is ); dox.normalize(); XPathExpression xpathExp = xPath.compile( "//*[local-name()='annotation']" ); NodeList annotationNodes = (NodeList) xpathExp.evaluate( dox, XPathConstants.NODESET ); // Remove each empty text node from document. for (int i = 0; i < annotationNodes.getLength(); i++) { Node annotationNode = annotationNodes.item(i); annotationNode.getParentNode().removeChild(annotationNode); } XPathExpression xpathExp2 = xPath.compile( "//text()[normalize-space(.) = '']" ); NodeList emptyTextNodes = (NodeList) xpathExp2.evaluate(dox, XPathConstants.NODESET ); for (int i = 0; i < emptyTextNodes.getLength(); i++) { Node emptyTextNode = emptyTextNodes.item(i); emptyTextNode.getParentNode().removeChild( emptyTextNode ); } TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer(); transformer.setOutputProperty( OutputKeys.INDENT, "yes" ); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); DOMSource domSrc = new DOMSource( dox ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); StreamResult result = new StreamResult( baos ); transformer.transform( domSrc, result ); return new String( baos.toByteArray() ); } }